﻿' (c) Copyright Microsoft Corporation.
' This source is subject to the Microsoft Public License (Ms-PL).
' Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
' All other rights reserved. 


Imports Coding4Fun.Kinect.Wpf

Imports Microsoft.Kinect
Imports Nui = Microsoft.Kinect

Imports MessageBox = System.Windows.MessageBox

<Assembly:CLSCompliant(True)>
Namespace Microsoft.Kinect.Samples.CursorControl
	''' <summary>
	''' Interaction logic for MainWindow.xaml
	''' </summary>
	Partial Public Class MainWindow
		Inherits Window
		Private Const ClickThreshold As Single = 0.33F
		Private Const SkeletonMaxX As Single = 0.60F
		Private Const SkeletonMaxY As Single = 0.40F


		Private _notifyIcon As New NotifyIcon()


		Public Sub New()
			InitializeComponent()

			' create tray icon
			_notifyIcon.Icon = New System.Drawing.Icon("CursorControl.ico")
			_notifyIcon.Visible = True
			AddHandler _notifyIcon.DoubleClick, Sub()
				Me.Show()
				Me.WindowState = WindowState.Normal
				Me.Focus()
			End Sub
		End Sub



		Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
			AddHandler kinectSensorChooser.KinectSensorChanged, AddressOf kinectSensorChooser_KinectSensorChanged
		End Sub

		Private Sub StopKinect(ByVal sensor As KinectSensor)
			If sensor IsNot Nothing Then
				If sensor.IsRunning Then
					sensor.Stop()
					sensor.AudioSource.Stop()
				End If
			End If
		End Sub

		Private Sub kinectSensorChooser_KinectSensorChanged(ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
			Dim old As KinectSensor = CType(e.OldValue, KinectSensor)

			StopKinect(old)

			Dim sensor As KinectSensor = CType(e.NewValue, KinectSensor)

			If sensor Is Nothing Then
				Return
			End If

			Dim parameters As New TransformSmoothParameters()
			parameters.Smoothing = 0.7F
			parameters.Correction = 0.3F
			parameters.Prediction = 0.4F
			parameters.JitterRadius = 1.0F
			parameters.MaxDeviationRadius = 0.5F

			sensor.SkeletonStream.Enable(parameters)
			sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30)
			sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30)

			AddHandler sensor.AllFramesReady, AddressOf sensor_AllFramesReady
			Try
				sensor.Start()
			Catch e1 As System.IO.IOException
				'another app is using Kinect
				kinectSensorChooser.AppConflictOccurred()
			End Try
		End Sub

		Private Sub sensor_AllFramesReady(ByVal sender As Object, ByVal e As AllFramesReadyEventArgs)
			sensor_DepthFrameReady(e)
			sensor_SkeletonFrameReady(e)
		End Sub


		Private Sub Window_Closed(ByVal sender As Object, ByVal e As EventArgs)
			' shut down the Kinect device
			_notifyIcon.Visible = False

			If kinectSensorChooser.Kinect IsNot Nothing Then
				kinectSensorChooser.Kinect.Stop()
			End If

		End Sub

		Private Sub Window_StateChanged(ByVal sender As Object, ByVal e As EventArgs)
			If WindowState = WindowState.Minimized Then
				Me.Hide()
			End If
		End Sub

		Private Sub sensor_SkeletonFrameReady(ByVal e As AllFramesReadyEventArgs)

			Using skeletonFrameData As SkeletonFrame = e.OpenSkeletonFrame()
				If skeletonFrameData Is Nothing Then
					Return
				End If

				Dim allSkeletons(skeletonFrameData.SkeletonArrayLength - 1) As Skeleton

				skeletonFrameData.CopySkeletonDataTo(allSkeletons)

				For Each sd As Skeleton In allSkeletons
					' the first found/tracked skeleton moves the mouse cursor
					If sd.TrackingState = SkeletonTrackingState.Tracked Then
						' make sure both hands are tracked
						If sd.Joints(JointType.HandLeft).TrackingState = JointTrackingState.Tracked AndAlso sd.Joints(JointType.HandRight).TrackingState = JointTrackingState.Tracked Then
							Dim cursorX, cursorY As Integer

							' get the left and right hand Joints
							Dim jointRight As Joint = sd.Joints(JointType.HandRight)
							Dim jointLeft As Joint = sd.Joints(JointType.HandLeft)

							' scale those Joints to the primary screen width and height
							Dim scaledRight As Joint = jointRight.ScaleTo(CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), SkeletonMaxX, SkeletonMaxY)
							Dim scaledLeft As Joint = jointLeft.ScaleTo(CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), SkeletonMaxX, SkeletonMaxY)

							' figure out the cursor position based on left/right handedness
							If LeftHand.IsChecked.GetValueOrDefault() Then
								cursorX = CInt(Fix(scaledLeft.Position.X))
								cursorY = CInt(Fix(scaledLeft.Position.Y))
							Else
								cursorX = CInt(Fix(scaledRight.Position.X))
								cursorY = CInt(Fix(scaledRight.Position.Y))
							End If

							Dim leftClick As Boolean

							' figure out whether the mouse button is down based on where the opposite hand is
							If (LeftHand.IsChecked.GetValueOrDefault() AndAlso jointRight.Position.Y > ClickThreshold) OrElse ((Not LeftHand.IsChecked.GetValueOrDefault()) AndAlso jointLeft.Position.Y > ClickThreshold) Then
								leftClick = True
							Else
								leftClick = False
							End If

							Status.Text = cursorX & ", " & cursorY & ", " & leftClick
							NativeMethods.SendMouseInput(cursorX, cursorY, CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), leftClick)

							Return
						End If
					End If
				Next sd
			End Using


		End Sub

		Private Sub sensor_DepthFrameReady(ByVal e As AllFramesReadyEventArgs)
			' if the window is displayed, show the depth buffer image
			If Me.WindowState = WindowState.Normal Then
				Using depthFrame As DepthImageFrame = e.OpenDepthImageFrame()
					If depthFrame Is Nothing Then
						Return
					End If

					video.Source = depthFrame.ToBitmapSource()
				End Using

			End If
		End Sub
	End Class
End Namespace
